% evaluate_schedule.m
% 封装了从接收一个调度方案到计算出最终性能指标的全过程。
% *** 已修改: 增加对 initial_scores 为空的特殊处理 ***
function [total_execution_time, total_spill_volume, solution, graph] = evaluate_schedule(initial_schedule, graph, code_map, caps, params, initial_scores)
    
    % 1. 执行内存分配与Spill决策
    [solution, graph] = perform_allocation(initial_schedule, graph, code_map, ...
                                             caps.l1, caps.ub, caps.l0a, caps.l0b, caps.l0c, ...
                                             params.min_farthest_use_threshold, ...
                                             params.w_use, params.w_vol, params.w_vic, ...
                                             params.alloc_strategy, ...
                                             0, 0);
    
    % 2. 对成功生成的解，增加一步额外的结果验证
    % (仅当 allocation 没有提前因 spill_failed 或 timed_out 失败时才需要执行)
    is_valid = true; % 默认为真
    if ~solution.timed_out && ~solution.spill_failed
        is_valid = validate_solution(solution, graph, code_map, caps.l1, caps.ub, caps.l0a, caps.l0b, caps.l0c);
    end

    % 3. 检查是否超时或失败，并施加惩罚
    if solution.timed_out
        fprintf('  !!! 评估警告: 调度执行步骤超限，判定为死循环。施加惩罚。!!!\n');
        
        % *** 新增: 处理首次评估时基准分不存在的情况 ***
        if isempty(initial_scores)
            % 如果是首次评估就超时，说明初始解本身有问题，给予最差惩罚
            total_execution_time = inf;
            total_spill_volume = inf;
        else
            % --- 平滑惩罚逻辑 ---
            progress_ratio = solution.nodes_processed / length(initial_schedule);
            penalty_factor = 10; 
            total_execution_time = initial_scores.time * (2 + penalty_factor * (1 - progress_ratio));
            total_spill_volume = solution.total_spill_volume + initial_scores.spill * (2 - progress_ratio);
        end
        
    elseif solution.spill_failed
        fprintf('  !!! 评估警告: 无法生成有效Spill方案。施加惩罚。!!!\n');
        
        % *** 此处逻辑完全复用 timed_out 的情况，以遵循"修改现有函数"的指令 ***
        if isempty(initial_scores)
            % 如果是首次评估就失败，给予最差惩罚。
            % 注意: 此处根据您的代码保留了 inf。如前所述，您已否决所有极大值方案，
            % 您需要根据您的最终决策替换此处的 inf 值。
            total_execution_time = inf;
            total_spill_volume = inf;
        else
            % --- 平滑惩罚逻辑 ---
            % 注意: 此处的 progress_ratio 是基于失败时的步数计算的
            progress_ratio = solution.nodes_processed / length(initial_schedule);
            penalty_factor = 10; 
            total_execution_time = initial_scores.time * (2 + penalty_factor * (1 - progress_ratio));
            total_spill_volume = solution.total_spill_volume + initial_scores.spill * (2 - progress_ratio);
        end

    elseif ~is_valid
        fprintf('  !!! 评估警告: 解评估后验证失败 (validate_solution 返回 false)。施加惩罚。!!!\n');

        if isempty(initial_scores)
            % 验证失败与超时/Spill失败同等严重，给予最差惩罚
            total_execution_time = inf;
            total_spill_volume = inf;
        else
            % --- 平滑惩罚逻辑 (进度为100%) ---
            % 因为 perform_allocation 已完整执行，所以进度视为 1.0
            progress_ratio = 1.0;
            penalty_factor = 10; 
            total_execution_time = initial_scores.time * (2 + penalty_factor * (1 - progress_ratio));
            total_spill_volume = solution.total_spill_volume + initial_scores.spill * (2 - progress_ratio);
        end

    else
        % --- 正常流程 ---
        total_spill_volume = solution.total_spill_volume;
        total_execution_time = calculate_total_time(solution, graph, code_map);
    end

end